#pragma once
#include <Core/System/System.hpp>
#include <Diablo/Root.hpp>
#include <Diablo/Constants.hpp>
#include <Diablo/Types.hpp>
#include <Diablo/Type/Item.hpp>

namespace Diablo
{
    /**/
    class Support
    {
    public:
        /**/
        static void IsolateGemBonuses( Item& item )
        {
            //TODO            
        }

        /**/
        static Bool SyncGemInfo( Item::Stat& stat )
        {
            stat.gem_type = GEM_TYPE_EMPTY;
            stat.gem_rank = 0;

            if(stat.values.GetCount() > 0)
            {
                ULong       value = static_cast<ULong>(NUMBER_WHOLE(stat.values[0]));
                GemStatId   stat_id;

                // parse gem stat
                if(!ITEM_GEM_STAT_IDS.FindObject(reinterpret_cast<Id&>(stat_id), stat.text, true))
                    return false;

                // get type from stat id
                switch(stat_id)
                {
                // amethyst
                case GEM_STAT_VITALITY:
                case GEM_STAT_LIFEP:
                case GEM_STAT_LIFEONHIT:
                    stat.gem_type = GEM_TYPE_AMETHYST;
                    break;

                // emerald
                case GEM_STAT_DEXTERITY:
                case GEM_STAT_GOLDFIND:
                case GEM_STAT_CRITICALHITDAMAGE:
                    stat.gem_type = GEM_TYPE_EMERALD;
                    break;

                // ruby
                case GEM_STAT_STRENGTH:
                case GEM_STAT_BONUSEXPERIENCE:
                case GEM_STAT_AVERAGEDAMAGE:
                    stat.gem_type = GEM_TYPE_RUBY;
                    break;

                // topaz
                case GEM_STAT_INTELLIGENCE:
                case GEM_STAT_MAGICFIND:
                case GEM_STAT_PHYSICALDAMAGETOATTACKER:
                    stat.gem_type = GEM_TYPE_TOPAZ;
                    break;

                default:
                    return false;
                }

                // get rank from stat value
                switch(stat_id)
                {
                case GEM_STAT_VITALITY:
                case GEM_STAT_DEXTERITY:
                case GEM_STAT_STRENGTH:
                case GEM_STAT_INTELLIGENCE:
                    stat.gem_rank = ((value - 6) / 4 + 1);
                    break;
                
                case GEM_STAT_GOLDFIND:
                case GEM_STAT_MAGICFIND:
                case GEM_STAT_BONUSEXPERIENCE:
                    stat.gem_rank = ((value - 5) / 2 + 1);
                    break;

                case GEM_STAT_LIFEP:
                    stat.gem_rank = (value - 4);
                    break;

                case GEM_STAT_LIFEONHIT:
                    stat.gem_rank = ITEM_GEM_LIFEONHIT.IndexOf(ITEM_GEM_LIFEONHIT.FlatSearch(value)) + 1;
                    break;

                case GEM_STAT_CRITICALHITDAMAGE:
                    stat.gem_rank = ITEM_GEM_CRITICALHITDAMAGE.IndexOf(ITEM_GEM_CRITICALHITDAMAGE.FlatSearch(value)) + 1;
                    break;

                case GEM_STAT_AVERAGEDAMAGE:
                    stat.gem_rank = ITEM_GEM_BONUSMINIMUMWEAPONDAMAGE.IndexOf(ITEM_GEM_BONUSMINIMUMWEAPONDAMAGE.FlatSearch(value)) + 1;
                    break;

                case GEM_STAT_PHYSICALDAMAGETOATTACKER:
                    stat.gem_rank = ITEM_GEM_PHYSICALDAMAGETOATTACKER.IndexOf(ITEM_GEM_PHYSICALDAMAGETOATTACKER.FlatSearch(value)) + 1;
                    break;
                }

                // sanity check
                if(stat.gem_rank > ITEM_GEM_RANK_LIMIT)
                    stat.gem_rank = 0;
            }

            return true;
        }

        /**/
        static void StripGemBonuses( Item& item )
        {
            // if weapon
            if(item.damage_min && item.damage_max && item.damage_aps)
            {
                Bool adjusted = false;

                // for each gem
                for( Item::SocketIterator i = item.sockets.Begin(); i != item.sockets.End(); ++i )
                {
                    // reduce damage by ruby bonus
                    if(i->gem_type == GEM_TYPE_RUBY && i->gem_rank > 0 && i->gem_rank <= ITEM_GEM_RANK_LIMIT)
                    {
                        ULong       damage = NUMBER(ITEM_GEM_BONUSMINIMUMWEAPONDAMAGE[i->gem_rank - 1], 0);
                        TextString  damage_string;

                        // check damage bonus modifier
                        if(ITEM_HOVER_STAT_IDS.FindName(damage_string, HOVER_STAT_PERCENTDAMAGE))
                        {
                            const Item::Stat* stat = item.FindStat(damage_string, false);
                            if(stat)
                            {
                                Double multiplier = 1.0 + NUMBER_TODOUBLE(stat->values[0]) / 100.0;

                                // adjust gem damage
                                damage = static_cast<ULong>(damage * multiplier);
                            }
                        }

                        // parse gem stat
                        item.damage_min -= damage;
                        item.damage_max -= damage;

                        adjusted = true;
                    }
                }

                // recalculate dps
                if(adjusted)
                    item.dpsarmor = ((item.damage_min + item.damage_max) * item.damage_aps / NUMBER_ACCURACY) / 2;
            }
        }
        /**/
        static void BuildItemHash( Item& item )
        {
            Char* id = item.hash;

            // include name
            id += sprintf(id, "%s", item.name);

            // and stats
            for( Item::StatIterator i = item.stats.Begin(); i != item.stats.End(); ++i )
                id += sprintf(id, "|%c:%u", *i->text, i->values.GetCount() ? i->values[0] : 0);

            // 0 terminate
            *id = 0;
        }
    };
}
